package com.javabi.codegenerator.java.object.executable;

import static com.javabi.codeobject.java.type.classtype.ClassType.CLASS;
import static com.javabi.codeobject.java.type.classtype.ClassType.INTERFACE;

import com.javabi.codegenerator.java.model.JavaModel;
import com.javabi.codegenerator.java.model.bean.JavaModelBean;
import com.javabi.codegenerator.java.model.executable.JavaModelExecutableSet;
import com.javabi.codegenerator.java.object.JavaObjectGenerator;
import com.javabi.codegenerator.java.object.executable.method.ExecutableMethod;
import com.javabi.codegenerator.java.object.model.IJavaContext;
import com.javabi.codegenerator.java.setup.ISetup;
import com.javabi.codeobject.java.block.field.JavaField;
import com.javabi.codeobject.java.block.method.IJavaMethod;
import com.javabi.codeobject.java.block.method.getter.GetterMethod;
import com.javabi.codeobject.java.block.method.setter.SetterMethod;
import com.javabi.codeobject.java.object.JavaObject;
import com.javabi.codeobject.java.type.IJavaType;
import com.javabi.codetype.bean.executable.IBeanExecutor;

public class JavaExecutableSetGenerator extends JavaObjectGenerator {

	private final JavaModelExecutableSet set;
	private IJavaType interfaceType;
	private IJavaType type;

	public JavaExecutableSetGenerator(ISetup setup, IJavaContext context, JavaModel model, JavaModelExecutableSet set) {
		super(setup, context, model, set.get());
		this.set = set;
	}

	public JavaModelExecutableSet getSet() {
		return set;
	}

	@Override
	public void registerPrimaryTypes() {
		interfaceType = registerJavaType("I" + getSet().getName(), INTERFACE);
		type = registerJavaType(getSet().getName(), CLASS);
	}

	@Override
	public void verifyReferencedTypes() {
	}

	@Override
	public void generate() {

		JavaObject objectInterface = new JavaObject(interfaceType);
		JavaObject object = new JavaObject(type);
		object.addExtends(interfaceType);

		// Fields
		JavaField executorField = new JavaField("executor", IBeanExecutor.class);
		executorField.setVolatile(true);
		executorField.setComment("The bean executor.");
		object.addBlock(executorField);

		// Methods
		object.addBlock(new GetterMethod(executorField));
		object.addBlock(new SetterMethod(executorField));
		addMethods(object, objectInterface);

		// Done!
		write(objectInterface);
		write(object);
	}

	private void addMethods(JavaObject object, JavaObject objectInterface) {
		for (JavaModelBean bean : getModel().getBeanList()) {
			if (bean.isExecutable()) {
				addMethod(object, objectInterface, bean);
			}
		}
	}

	private void addMethod(JavaObject object, JavaObject objectInterface, JavaModelBean bean) {

		// Object
		IJavaMethod method = new ExecutableMethod(bean);
		method.setOverride();
		object.addBlock(method);

		// Interface
		method = new ExecutableMethod(bean);
		method.setInterface(true);
		objectInterface.addBlock(method);
	}

}
